//
//  NSObject+MKUITheme.m
//  MKUI
//
//  Created by 苏尚进 on 2021/3/20.
//  Copyright © 2021 moon. All rights reserved.
//

#import "NSObject+MKUITheme.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>

NSString *const kMKUIThemeUpdateNotification=@"kMKUIThemeUpdateNotification";
#define __mkthemePickersProperty__ "__mkthemePickersProperty__"
@implementation NSObject (MKUITheme)

- (NSMutableDictionary<NSString *,id<MKUIThemePickerProtocol>> *)__mkthemePickers{
    NSMutableDictionary<NSString *,id<MKUIThemePickerProtocol>> *allPickers = objc_getAssociatedObject(self, __mkthemePickersProperty__);
    if(!allPickers){
        allPickers = [[NSMutableDictionary alloc] init];
    }
    return allPickers;
}
- (NSDictionary<NSString *,id<MKUIThemePickerProtocol>> *)mkthemePickers{
    NSDictionary<NSString *,id<MKUIThemePickerProtocol>> *allPickers = objc_getAssociatedObject(self, __mkthemePickersProperty__);
    return allPickers;
}
- (void)setMkthemePickers:(NSDictionary<NSString *,id<MKUIThemePickerProtocol>> *)mkthemePickers{
    objc_setAssociatedObject(self, __mkthemePickersProperty__, mkthemePickers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kMKUIThemeUpdateNotification object:nil];
    if(mkthemePickers.count!=0){
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(__MKUITheme_refreshTheme) name:kMKUIThemeUpdateNotification object:nil];
    }
}
- (void)__MKUITheme_refreshTheme{
    NSDictionary<NSString *,id<MKUIThemePickerProtocol>> *allPickers = [[self mkthemePickers] copy];
    [UIView animateWithDuration:0.25 animations:^{
        for (id<MKUIThemePickerProtocol> picker in [allPickers allValues]) {
            [picker applyThemeTo:self];
        }
    }];
}
- (void)mktheme_setPicker:(nullable id<MKUIThemePickerProtocol>)picker{
    NSMutableDictionary<NSString *,id<MKUIThemePickerProtocol>> *allPickers = [self __mkthemePickers];
    allPickers[picker.pickerKey] = picker;
    self.mkthemePickers = allPickers;
    [picker applyThemeTo:self];
}
- (void)mktheme_removePickerForKey:(NSString *)key{
    NSMutableDictionary<NSString *,id<MKUIThemePickerProtocol>> *allPickers = [self __mkthemePickers];
    if(allPickers.count!=0){
        [allPickers removeObjectForKey:key];
        self.mkthemePickers = allPickers;
    }
}
- (nullable id<MKUIThemePickerProtocol>)mktheme_getPickerForKey:(NSString *)key{
    NSMutableDictionary<NSString *,id<MKUIThemePickerProtocol>> *allPickers = [self __mkthemePickers];
    return allPickers[key];
}

- (id)mktheme_performSelector:(SEL)aSelector{
    id result = nil;
    NSMethodSignature *sig = [self methodSignatureForSelector:aSelector];
    const char *methodReturnType = sig.methodReturnType;
    NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sig];
    invo.target = self;
    invo.selector = aSelector;
    /*
     c ： char
     i ： int
     s ： short
     l ： long 在64位程序中，l为32位。
     q ： long long
     C ： unsigned char
     I ： unsigned int
     S ： unsigned short
     L ： unsigned long
     Q ： unsigned long long
     f ： float
     d ： double
     B ： C++标准的bool或者C99标准的_Bool
     v ： void
     * ： 字符串（char *）
     @ ： 对象（无论是静态指定的还是通过id引用的）
     # ： 类（Class）
     : ： 方法选标（SEL）
     [array type] ： 数组
     {name=type...} ： 结构体
     (name=type...) ： 联合体
     bnum ： num个bit的位域
     ^type ： type类型的指针
     ? ： 未知类型（其它时候，一般用来指函数指针）
     */
    if(strcmp(methodReturnType, @encode(void))==0){
        [invo invoke];
        result = nil;
    }else if(strcmp(methodReturnType, @encode(char))==0){
        [invo invoke];
        char v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(int))==0){
        [invo invoke];
        int v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(short))==0){
        [invo invoke];
        short v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(long))==0){
        [invo invoke];
        long v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(long long))==0){
        [invo invoke];
        long long v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(unsigned char))==0){
        [invo invoke];
        unsigned char v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(unsigned int))==0){
        [invo invoke];
        unsigned int v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(unsigned short))==0){
        [invo invoke];
        unsigned short v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(unsigned long))==0){
        [invo invoke];
        unsigned long v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(unsigned long long))==0){
        [invo invoke];
        unsigned long long v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(float))==0){
        [invo invoke];
        float v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(double))==0){
        [invo invoke];
        double v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(BOOL))==0){
        [invo invoke];
        BOOL v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(strcmp(methodReturnType, @encode(char *))==0){
        [invo invoke];
        char *v;
        [invo getReturnValue:&v];
        result = @(v);
    }else if(*methodReturnType == '{'){
        //结构体
        [invo invoke];
        void * v;
        [invo getReturnValue:&v];
        result = [NSValue value:&v withObjCType:methodReturnType];
    }else{//调用原来的performSelector:，返回对象
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        result = [self performSelector:aSelector];
        #pragma clang diagnostic pop
    }
    return result;
}
@end

//#ifdef DEBUG
//#import <UIKit/UIKit.h>
//#import "NSString+MKUITheme.h"
//@interface TestPerformObject:NSObject
//@property(nonatomic,assign) UIViewContentMode valueOfUIViewContentMode;
//@property(nonatomic,assign) NSInteger valueOfNSInteger;
//@property(nonatomic,assign) CGSize valueOfCGSize;
//@end
//@implementation TestPerformObject
//- (void)setTestValue{
//    self.valueOfUIViewContentMode = UIViewContentModeTop;
//    self.valueOfNSInteger = 100;
//    self.valueOfCGSize = CGSizeMake(44, 44);
//}
//- (void)setValueOfNSInteger:(NSInteger)valueOfNSInteger{
//    _valueOfNSInteger = valueOfNSInteger;
//}
//- (void)setValueOfCGSize:(CGSize)valueOfCGSize{
//    _valueOfCGSize = valueOfCGSize;
//}
//- (void)setValueOfUIViewContentMode:(UIViewContentMode)valueOfUIViewContentMode{
//    _valueOfUIViewContentMode = valueOfUIViewContentMode;
//}
//- (void)setValue:(id)value forName:(NSString *)name{
//    SEL selector = [NSString mktheme_setSelectorForProperty:name];
//    void (*mp)(id, SEL,CGSize) = (void (*)(id, SEL,CGSize))[self methodForSelector:selector];
//    mp(self,selector,[(NSValue *)value CGSizeValue]);
//}
//+ (void)load{
//    TestPerformObject *obj = [[TestPerformObject alloc] init];
//    [obj setTestValue];
//    TestPerformObject *obj2 = [[TestPerformObject alloc] init];
////    {
////        //NSNumber需要转换为int类型，才能成功设置
////        NSString *name = @"valueOfUIViewContentMode";
//////        id value0 = [obj performSelector:NSSelectorFromString(name)];//会闪退
//////        NSLog(@"value0:%@",value0);
////        id value1 = [obj mktheme_performSelector:NSSelectorFromString(name)];
////        [obj2 setValue:value1 forName:name];
////        if(obj.valueOfUIViewContentMode!=obj2.valueOfUIViewContentMode){
////            NSLog(@"error:%@",name);
////        }
////        NSLog(@"value1:%@",value1);
////    }
////    {
////        //NSNumber需要转换为int类型，才能成功设置
////        NSString *name = @"valueOfNSInteger";
//////        id value0 = [obj performSelector:NSSelectorFromString(name)];//会闪退
//////        NSLog(@"value0:%@",value0);
////        id value1 = [obj mktheme_performSelector:NSSelectorFromString(name)];
////        [obj2 setValue:value1 forName:name];
////        if(obj.valueOfNSInteger!=obj2.valueOfNSInteger){
////            NSLog(@"error:%@",name);
////        }
////        NSLog(@"value1:%@",value1);
////    }
////    {//NSValue需要转换为struct类型，才能成功设置
////        NSString *name = @"valueOfCGSize";
//////        id value0 = [obj performSelector:NSSelectorFromString(name)];//会闪退
//////        NSLog(@"value0:%@",value0);
////        id value1 = [obj mktheme_performSelector:NSSelectorFromString(name)];
////        [obj2 setValue:value1 forName:name];
////        if(!CGSizeEqualToSize(obj.valueOfCGSize, obj2.valueOfCGSize)){
////            NSLog(@"error:%@",name);
////        }
////        NSLog(@"value1:%@",value1);
////    }
//}
//@end
//#endif

//@interface TestProperty : NSObject
//@property(nonatomic,strong) NSString *name;
//@end
//@interface TestObj : NSObject
//- (TestProperty *)prop;
//@end
//@implementation TestProperty
//- (void)dealloc{
//    NSLog(@"dealloc:TestProperty");
//}
//@end
//@implementation TestObj
//- (void)dealloc{
//    NSLog(@"dealloc:TestObj");
//}
//- (TestProperty *)prop{
//    return [[TestProperty alloc] init];
//}
//+ (void)load{
//    NSLog(@"begin");
//    id value;
//    @autoreleasepool {
//        TestObj *obj = [[TestObj alloc] init];
//        value = [obj performSelector:NSSelectorFromString(@"prop")];
//    }
//
//    NSLog(@"value:%@",value);
//    NSLog(@"end");
//}
//@end
